/*:
* @plugindesc (v1.13)全場狀態-戰場屬性系統.
* @author 小c
* @version 1.0.6
* @date 1/21/2020
*
* @param Default Global State Count Max
* @text 默認全場狀態最大層數
* @type number
* @min 0
* @default 1
* @desc 這裡0表示無限層數
*
* @param Element List
* @text 戰場屬性列表
* @type struct<elementData>[]
* @default []
*
* @param Element Total Count Function
* @text 戰場屬性層數變換函數
* @type note
* @default "return this.globalElementCount(elementId);"
* @desc 戰場屬性層數的運算函數，參數說明請看插件的說明文件。
*
* @param Element Count Text
* @text 戰場屬性提示文字
* @type struct<elementText>
* @default {"text":"%1+","font":"GameFont","size":"18"}
*
* @param Element Home X
* @text 戰場屬性中心X
* @type note
* @desc 召喚戰場屬性圖示出現的默認位置，之後圖示運動到顯示屬性狀態的位置，參數：elementId
* @default "return Graphics.boxWidth / 2;"
*
* @param Element Home Y
* @text 戰場屬性中心Y
* @type note
* @desc 召喚戰場屬性圖示出現的默認位置，之後圖示運動到顯示屬性狀態的位置，參數：elementId
* @default "return Graphics.boxHeight / 2;"
*
* @param Element Move Time
* @text 召喚戰場屬性的運動時間
* @type number
* @default 60
* @desc 召喚戰場屬性的運動時間（幀）
*
* @param Element Opacity Min
* @text 召喚戰場屬性最低不透明度
* @type number
* @min 0
* @max 255
* @default 125
* @desc 戰場屬性入場時，精靈不透明度從該值逐漸增加至255，退場時，從255逐漸減少至該值
*
* @help
* 全場狀態-戰場屬性
* 若使用了YEP戰鬥序列，請放在戰鬥序列的下面
* 若使用了YEP狀態核心，請放在狀態核心的下面
* 若本插件版本在1.10以上，不可以將狀態對象寫入存檔
*
* 請優先配置插件參數。
* 
* 狀態標籤
* <Global State Type: type>
* 全場狀態類型，type可取值為
* all：影響全場敵我目標
* party：影響全體我方
* troop：影響全體敵方
* custom：自定義影響範圍
* element：影響戰場屬性，屬性將影響技能物品的使用及效果
*
* <Global State Area Custom>
* // JavaScript code
* targets.push($gameParty.leader());
* targets.push($gameTroop.members()[0]);
* </Global State Area Custom>
* 自定義全場狀態影響範圍，targets數組中的目標會受影響。
* 變量state表示當前配置的狀態。
* 當狀態類型為custom時才有效。
*
* <State Element: x>
* 指定戰場屬性，配置屬性列表中一個屬性的id值。
* 對任意全場狀態均有效，即使類型不是element。
*
* <Global State Count Max: x>
* 指定全場狀態的最大疊加層數，x為整數
* 如果配置為0，表示層數無限制。
* 如果不配置，以插件參數為準。
*
* <Global Next State: x>
* 對多層全場狀態生效，指定該狀態的下級狀態為x，x為狀態id
* 若一個全場狀態有trait效果且有n層，則總trait效果為：
* 當前狀態 + (n -1)個下級狀態的所有trait對象的疊加
* 若不配置，下級狀態就是當前狀態。
*
* 關於【戰場屬性列表】的配置方法
* 該參數各分項是戰場屬性的列表項，各分項配置方法如下：
* 元素名：管理用，默認不參與其他功能。
* 元素標籤：字符串，建議以英文+下劃線形式命名，不可以有空格。
* 我們假設某個元素的標籤名是FIRE，則有
* （1）戰鬥中，表達式【CP.FIRE】表示該元素的總層數，此總層數已經過戰場
* 屬性層數變換。
* （2）戰場屬性變換函數中，elementArr.FIRE表示該元素的默認層數。
* 元素圖：戰鬥中有改元素時展示的圖片素材
* 原點X，原點Y：元素圖的錨點
* 元素座標X，元素座標Y：元素圖的顯示座標。
* 注意：戰場屬性的id就是該項在列表的位置，從1起。
* 即第一項戰場屬性id=1，第二項id=2，以此類推。
*
* 關於【全場狀態的層數】
* 全場狀態允許疊層，可以通過額外代碼使疊層產生效果。
* 同時，戰場屬性的層數與對應狀態的層數相關。
* 默認情況下，一個戰場屬性的總層數是所有相關全場狀態的層數和。
* 如果你想讓各個戰場屬性在層數上相互影響，請配置【戰場屬性層數變換
* 函數】。
* 該函數有兩個參數，分述如下：
* elementId：當前需要求解層數的戰場屬性id
* elementArr：對象，保存所有戰場屬性的默認層數
* elementArr.FIRE表示symbol為FIRE的戰場屬性的默認層數。
* 返回值為戰場屬性elementId的最終層數
*
* 全場狀態額外代碼
* <Custom Add Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   if(actor.hpRate() < 0.5)
*       actor.addState(actor.deathStateId());
* });
* </Custom Add Global State Eval>
* 全場狀態添加時執行的額外代碼
* 
* <Custom Remove Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   actor.gainHp(-Math.round(actor.mhp / 2));
*   actor.gainMp(-Math.round(actor.mmp / 2));
*   actor.startDamagePopup();
* });
* </Custom Remove Global State Eval>
* 全場狀態解除時執行的額外代碼
* 
* <Custom Update Global State Eval>
* //JavaScript code
* $gameParty.battleMembers().forEach(function(actor){
*   actor.gainHp(-Math.round(actor.mhp / 10));
*   actor.startDamagePopup();
* });
* </Custom Update Global State Eval>
* 全場狀態存在時每回合都會執行的額外代碼
*
* <Custom EndAction Global State Eval>
* //JavaScript code
* if(subject.isActor())
*   subject.gainExp(2);
* </Custom EndAction Global State Eval>
* 全場狀態存在時每次行動後都會執行的額外代碼
* 注意：只要這個全場狀態存在，戰鬥中任何行動結束時都會執行代碼。
* 如果你只需要被影響的目標執行內容，請配置YEP狀態核心。
*
* 在上述四個額外代碼中有以下共用變量
* subject表示當前行動的發起方，只在EndAction中使用
* this指向BattleManager對象本身
* 
* 物品/技能標籤 
* <Add Global State: x>
* 使用該物品/技能時添加全場狀態x
* <Add Global Count: count>
* 上文中指定添加的全場狀態x疊加count層
* 
* <Remove Global State: x>
* 使用該物品/技能時解除全場狀態x
* <Remove Global Count: count>
* 上文中指定移除的全場狀態移除count層
* <Remove Global State Completely>
* 完全移除上文指定的全場狀態
* 注意：有以上五個標籤的物品只能在戰鬥中使用
* 
* <Battle Element: x, x, x>
* 物品/技能需要的戰場屬性數值，可多個。
* <Battle Element: 1> 技能物品需要戰場屬性1
* <Battle Element: 2, 3, 5> 技能物品需要戰場屬性2，屬性3，屬性5，當三種屬
* 性全部存在時滿足條件。
* 滿足條件時指定的技能物品才能被使用。
*
* 若使用了YEP戰鬥序列插件，則可以使用下面的戰鬥序列指令：
* Add Global State: x, [count] 添加全場狀態x count層，count可選，省略為1
* Remove Global State: x, [count] 解除全場狀態x count層，count可選，省略為1
* 在Remove指令中count可取字符串all，表示完全移除狀態
* 例子：
* Add Global State: 10, 2 添加全場狀態10 2層
* Remove Global State: 10 解除全場狀態10 1層
*
* 插件指令（只能在戰鬥中使用）
* GlobalState add x count 添加全場狀態x count層
* GlobalState remove x 移除全場狀態x count層
* 如果count參數省略，表示變更1層
* 在remove指令中count可取字符串all，表示完全移除狀態
* 例子：
* GlobalState add 10 3 添加全場狀態10 3層
* GlobalState remove 10 解除全場狀態10 1層
* GlobalState remove 10 all 完全解除全場狀態10
*
* 此外，亦可用腳本添加或移除全場狀態
* BattleManager.addGlobalState(stateId, count); 添加全場狀態若干層
* BattleManager.removeGlobalState(stateId, count); 移除全場狀態若干層
* BattleManager.removeGlobalStateCompletely(stateId) 完全移除一個全場狀態
* 以上三個函數返回布爾值，表示是否執行成功
* 注意：以上三個函數不執行戰場屬性圖示的刷新
*
* 刷新屬性圖示，使用下面的函數：
* BattleManager.requestElementSpritesUpdate(elementId)
* 刷新指定戰場屬性的圖示的顯示狀態
* BattleManager.requestElementSpritesUpdateAll()
* 刷新所有戰場屬性的圖示的顯示狀態
* BattleManager.addMovableElement(elenentId, moveType, success)
* 召喚一個移動的屬性圖示
* elementId：指定戰場屬性id
* moveType：移動類型，只有兩個值可選
* （1）Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD：添加屬性時
* （2）Sprite_MovableGlobalElement.MOVE_TYPE_BACK：移除屬性時
* success：布爾值，狀態是否變更成功，true時才會正常出現移動圖示
* 當這個移動圖示到位時，會自動刷新一次戰場屬性圖示狀態
*
* 戰鬥開始時，可指定立即添加的全場狀態
* 以下標籤可添加至全場狀態的備註中
* <Global State Auto Add Condition: Always>
* 無條件使該狀態戰鬥開始時添加
* <Global State Auto Add Condition: Switch x, x, x>
* 若干變量為on時，滿足條件
* <Global State Auto Add Condition: Variable x, Above y>
* 變量x值大於y時滿足條件
* <Global State Auto Add Condition: Variable x, Below y>
* 變量x值小於y時滿足條件
* <Global State Auto Add Condition: Variable x, Range y1, y2>
* 變量x值在閉區間[y1,y2]時滿足條件，此項必須滿足y1<y2
* <Global State Auto Add Condition Eval>
* //JS代碼
* condition = $gameParty.gold() > 10000;
* </Global State Auto Add Condition Eval>
* 變量condition=true時滿足條件
* 以上所有內容可以組合配置，所有條件滿足判定為滿足條件
* 滿足條件時該全場狀態在戰鬥開始時即添加
* Always除外，帶有Always條件的全場狀態忽略其他內容，判定為滿足條件
* 默認情況下，戰鬥開始立即添加的狀態只有一層，若需要添加多層，有以下
* 標籤：
* 下面的標籤添加至全場狀態的備註中
* <Global State Auto Add Count Eval>
* //JS代碼
* count = Math.min(5, Math.round($gameParty.gold() / 1000));
* if(count < 1)
*   count = 1;
* </Global State Auto Add Count Eval>
* 當該狀態滿足自動添加條件時配置本標籤才有效
* this表示BattleManager對象，最終count>=1才滿足條件
*
* 其他JavaScript函數
* BattleManager.isGlobalStateAffected(stateId) 戰場是否存在指定狀態
* BattleManager.hasGlobalElement(elementId) 戰場是否存在指定屬性
* BattleManager.requestGlobalStatesChange() 請求戰場刷新所有已有狀態
* 該函數在全場狀態添加移除時將會主動調用
* BattleManager.refreshGlobalStateMembers() 刷新所有全場狀態的影響目標
* 該函數在上一函數內以及戰鬥者的refresh中主動調用
*
* 補充：技能/物品的製作方法
* 1. 標籤法：用標籤定義添加/移除的狀態和層數
* 2. 序列法：使用YEP戰鬥序列指令執行操作
* 3. 公共事件法：使用公共事件調用插件指令實現效果
* 方法1只能做單狀態變化，執行效果在技能/道具動畫之前
* 方法2和3相對自由，可以多狀態變化，3一般在動畫執行後
* 
* 更新日誌 
* v1.00
* 插件完成
*
* v1.01
* 修復非戰場屬性型狀態在戰鬥者上的顯示偏差
*
* v1.02
* 修復需戰場屬性才可使用的戰鬥物品在沒有戰場屬性時不顯示的問題
*
* v1.03
* 追加狀態添加、解除、回合更新時執行額外代碼
*
* v1.04
* 修復遊戲在沒有進過戰鬥的情況下進入技能界面報錯的問題
*
* v1.05
* 修復全場狀態在戰鬥結束後依然生效的BUG
*
* v1.06
* 修復全場狀態持續回合數顯示錯誤的問題
*
* v1.07
* 添加技能添加移除全場狀態的標籤
* 支持通過YEP戰鬥序列指令調整全場狀態
*
* v1.08
* 添加戰鬥開始自動添加全場狀態的功能
* 全場狀態支持在行動結束時執行額外代碼
*
* v1.09
* 解決YEP-ATB戰鬥模式下，使用EndAction額外代碼調用公共事件不會立即執行
* 的問題
*
* v1.10
* 優化算法性能，使狀態運算不再是每次調用
* 將所有代碼字符串轉化為函數
*
* v1.11
* 取消戰場屬性的element類型限制
* 添加全場狀態的層數與戰場屬性的層數定義
* 添加戰場屬性層數的自定義表示
* 添加戰場屬性的圖示UI配置
*
* v1.12
* 增加全場狀態最大層數的默認值
* 修復標籤型技能需要設定目標的問題
*
* v1.13
* 修復不指定自動添加層數時無法在戰鬥開始時添加狀態的問題
* 如果不指定自動添加層數，默認為1
*/
/*~struct~elementData:
 * @param name
 * @text 元素名
 *
 * @param symbol
 * @text 元素標籤
 * @desc 標籤名，JS調用使用，如果標籤名為A，則elementObject.A表示該元素的層數
 *
 * @param image
 * @text 元素圖
 * @type file
 * @dir img/system
 * @desc 戰鬥中顯示的元素精靈圖
 *
 * @param anchorX
 * @text 原點X
 * @type number
 * @decimals 2
 * @min 0
 * @max 1
 * @default 0.50
 *
 * @param anchorY
 * @text 原點Y
 * @type number
 * @decimals 2
 * @min 0
 * @max 1
 * @default 0.50
 *
 * @param posX
 * @text 元素座標X
 * @type note
 * @default "return elementId * 60;"
 * @desc 函數，this對象為Scene_Battle，elementId為元素序號，從1起。
 *
 * @param posY
 * @text 元素座標Y
 * @type note
 * @default "return 0;"
 * @desc 函數，this對象為Scene_Battle，elementId為元素序號，從1起。
 *
 * @param countColor
 * @text 元素層數文字顏色
 * @default #FFFF40
 *
 * @param countX
 * @text 元素層數文字X
 * @type note
 * @default "return 0;"
 *
 * @param countY
 * @text 元素層數文字Y
 * @type note
 * @default "return 0;"
 */
/*~struct~elementText:
 * @param text
 * @text 提示文字
 * @default %1+
 * @desc %1表示當前元素的疊加層數
 *
 * @param font
 * @text 文字字體
 * @default GameFont
 *
 * @param size
 * @text 文字大小
 * @type number
 * @default 18
 */

var Imported = Imported || {};
Imported.CP_GlobalState = true;

var CP = CP || {};
CP.GlobalManager = CP.GlobalManager || {};
CP.GlobalManager.Param = PluginManager.parameters("CP_GlobalState");
CP.GlobalManager.DEFAULT_GLOBAL_STATE_COUNT_MAX = Number(CP.GlobalManager.Param["Default Global State Count Max"]) || 0;
CP.GlobalManager.GLOBAL_ELEMENT_LIST = JSON.parse(CP.GlobalManager.Param["Element List"]).map(function(itemStr, index){
	var item = JSON.parse(itemStr);
	item.id = index + 1;
	item.name = item.name.trim();
	item.symbol = item.symbol.trim();
	item.image = ImageManager.loadSystem(item.image);
	item.anchorX = Number(item.anchorX) || 0;
	item.anchorY = Number(item.anchorY) || 0;
	item.posX = new Function("elementId", JSON.parse(item.posX));
	item.posY = new Function("elementId", JSON.parse(item.posY));
	item.countColor = item.countColor.trim();
	item.countX = new Function("elementId", JSON.parse(item.countX));
	item.countY = new Function("elementId", JSON.parse(item.countY));
	return item;
});

CP.GlobalManager.GLOBAL_ELEMENT_TOTAL_COUNT_FUNCTION = new Function("elementId", "elementArr"
	, JSON.parse(CP.GlobalManager.Param["Element Total Count Function"]));

CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA = JSON.parse(CP.GlobalManager.Param["Element Count Text"]);
CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text = CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text.trim();
CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size = Number(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size) || 18;

CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION = {
	x: new Function("elementId", JSON.parse(CP.GlobalManager.Param["Element Home X"])),
	y: new Function("elementId", JSON.parse(CP.GlobalManager.Param["Element Home Y"]))
};

CP.GlobalManager.GLOBAL_ELEMENT_MOVE_TIME = Number(CP.GlobalManager.Param["Element Move Time"]) || 0;
CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN = Number(CP.GlobalManager.Param["Element Opacity Min"]) || 0;

//全場狀態類型
CP.GlobalManager.GLOBAL_TYPE_NONE = 0;//非全場狀態
CP.GlobalManager.GLOBAL_TYPE_ALL = 1; //全場狀態，影響所有人
CP.GlobalManager.GLOBAL_TYPE_PARTY = 2; //全場狀態，影響我方
CP.GlobalManager.GLOBAL_TYPE_TROOP = 3; //全場狀態，影響敵方
CP.GlobalManager.GLOBAL_TYPE_CUSTOM = 4; //全場狀態，自定義影響範圍
CP.GlobalManager.GLOBAL_TYPE_ELEMENT = 5 //全場狀態，屬性祭符

//額外代碼執行時機
CP.GlobalManager.GLOBAL_EVAL_ADD = 1;
CP.GlobalManager.GLOBAL_EVAL_REMOVE = 2;
CP.GlobalManager.GLOBAL_EVAL_UPDATE = 3;
CP.GlobalManager.GLOBAL_EVAL_END_ACTION = 4;

//數據庫註釋讀取
CP.GlobalManager._loaded = false;
CP.GlobalManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.GlobalManager.DATABASE_LOADED.call(this))
		return false;

	if(!CP.GlobalManager._loaded){
		CP.GlobalManager.loadGlobalStates();
		CP.GlobalManager.loadGlobalStatesCustomArea();
		CP.GlobalManager.loadGlobalStatesCustomEval();
		CP.GlobalManager.loadGlobalStateAutoAdd();

		CP.GlobalManager.loadItemGlobalStatesAction($dataSkills);
		CP.GlobalManager.loadItemGlobalStatesAction($dataItems);	

		CP.GlobalManager.loadElementCondition($dataSkills);
		CP.GlobalManager.loadElementCondition($dataItems);

		CP.GlobalManager._loaded = true;
	}

	return true;
};

CP.GlobalManager.loadGlobalStates = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalType = this.GLOBAL_TYPE_NONE;
		state.globalElement = 0;
		state.globalStateCountMax = 0; //狀態層數最大值
		state.globalNextState = 0; //下級狀態

		if(state.meta["Global State Type"]){
			var type = state.meta["Global State Type"].trim().toUpperCase();
			switch(type){
				case "ALL":
					state.globalType = this.GLOBAL_TYPE_ALL;
					break;
				case "PARTY":
					state.globalType = this.GLOBAL_TYPE_PARTY;
					break;
				case "TROOP":
					state.globalType = this.GLOBAL_TYPE_TROOP;
					break;
				case "CUSTOM":
					state.globalType = this.GLOBAL_TYPE_CUSTOM;
					break;
				case "ELEMENT":
					state.globalType = this.GLOBAL_TYPE_ELEMENT;
			}
		}

		if(state.globalType !== this.GLOBAL_TYPE_NONE){
			state.globalStateCountMax = this.DEFAULT_GLOBAL_STATE_COUNT_MAX; //0表示無限疊層
			state.globalNextState = i; //默認下級狀態是自身
			if(state.meta["Global State Count Max"])
				state.globalStateCountMax = Number(state.meta["Global State Count Max"]) || 0;
			if(state.meta["Global Next State"])
				state.globalNextState = Number(state.meta["Global Next State"]) || i;
			if(state.meta["State Element"]){
				var el = Number(state.meta["State Element"]) || 0;
				state.globalElement = el > 0 ? el : 0;
			}
		}
	}
};

CP.GlobalManager.loadGlobalStatesCustomArea = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalCustomAreaEval = null;
		if(state.globalType !== this.GLOBAL_TYPE_CUSTOM)
			continue;

		if(state.meta["Global State Area Custom"]){
			var reg = /<Global State Area Custom>([\S\s]*)<\/Global State Area Custom>/;
			reg.exec(state.note);

			state.globalCustomAreaEval = new Function("var targets = [];\n" + RegExp.$1 + "\nreturn targets;");
		}
	}
};

CP.GlobalManager.loadGlobalStatesCustomEval = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalCustomEval = {};

		if(state.meta["Custom Add Global State Eval"]){
			var reg = /<Custom Add Global State Eval>([\s\S]*)<\/Custom Add Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.add = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom Remove Global State Eval"]){
			var reg = /<Custom Remove Global State Eval>([\s\S]*)<\/Custom Remove Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.remove = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom Update Global State Eval"]){
			var reg = /<Custom Update Global State Eval>([\s\S]*)<\/Custom Update Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.update = new Function("subject", RegExp.$1);
		}

		if(state.meta["Custom EndAction Global State Eval"]){
			var reg = /<Custom EndAction Global State Eval>([\s\S]*)<\/Custom EndAction Global State Eval>/;
			reg.exec(state.note);
			state.globalCustomEval.endAction = new Function("subject", RegExp.$1);
		}
	}
};

CP.GlobalManager.loadGlobalStateAutoAdd = function(){
	for(var i = 1; i < $dataStates.length; i++){
		var state = $dataStates[i];
		state.globalAutoAddData = {};
		state.globalAutoAddData.always = false;
		this.loadGlobalStateAutoAddData(state);
		this.loadGlobalStateAutoAddEvalCondition(state);
		this.loadGlobalStateAutoAddCount(state);
	}
};

CP.GlobalManager.loadGlobalStateAutoAddData = function(state){
	var reg1 = /<Global State Auto Add Condition: Switch ([^<>]+)>/;
	var reg2 = /<Global State Auto Add Condition: Variable (\d+), Above ([+-]?\d+(\.\d+)*)>/;
	var reg3 = /<Global State Auto Add Condition: Variable (\d+), Below ([+-]?\d+(\.\d+)*)>/;
	var reg4 = /<Global State Auto Add Condition: Variable (\d+), Range ([+-]?\d+(\.\d+)*), ([+-]?\d+(\.\d+)*)>/;
	var reg5 = /<Global State Auto Add Condition: Always>/;

	var notes = state.note.split("\n");
	state.globalAutoAddData.switches = [];
	state.globalAutoAddData.variables = [];

	for(var i = 0; i < notes.length; i++){
		var note = notes[i];
		if(reg1.exec(note)){
			//開關
			var switches = RegExp.$1.split(",").map(function(n){
				return Number(n) || 0;
			});
			for(var k = 0; k < switches.length; k++){
				var sn = switches[k];
				if(sn > 0 && !state.globalAutoAddData.switches.contains(sn))
					state.globalAutoAddData.switches.push(sn);
			}
		}else if(reg2.exec(note)){
			//變量 大於min
			var v = Number(RegExp.$1) || 0;
			var value = Number(RegExp.$2) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, value, null))
		}else if(reg3.exec(note)){
			//變量 小於 max
			var v = Number(RegExp.$1) || 0;
			var value = Number(RegExp.$2) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, null, value));
		}else if(reg4.exec(note)){
			var v = Number(RegExp.$1) || 0;
			var value1 = Number(RegExp.$2) || 0;
			var value2 = Number(RegExp.$4) || 0;
			state.globalAutoAddData.variables.push(this.getVariableConditionData(v, value1, value2));
		}else if(reg5.exec(note))
			state.globalAutoAddData.always = true;
	}
};

CP.GlobalManager.getVariableConditionData = function(variableId, min, max){
	return {variableId: variableId, min: min, max: max};
}

CP.GlobalManager.loadGlobalStateAutoAddEvalCondition = function(state){
	var reg = /<Global State Auto Add Condition Eval>([\s\S]*?)<\/Global State Auto Add Condition Eval>/;
	state.globalAutoAddData.eval = null;
	if(reg.exec(state.note)){
		state.globalAutoAddData.eval = new Function("var condition = false;\n" + RegExp.$1.trim() 
			+ "\nreturn condition;");
	}
};

CP.GlobalManager.loadGlobalStateAutoAddCount = function(state){
	var reg = /<Global State Auto Add Count Eval>([\s\S]*?)<\/Global State Auto Add Count Eval>/;
	state.globalAutoAddData.count = null;
	if(reg.exec(state.note)){
		state.globalAutoAddData.count = new Function("var count = 0;\n" + RegExp.$1.trim() + "\nreturn count;");
	}
};

CP.GlobalManager.loadItemGlobalStatesAction = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.addGlobalStateId = 0;
		item.removeGlobalStateId = 0;
		item.addGlobalCount = 0;
		item.removeGlobalCount = 0;
		item.removeGlobalCompletely = false; //完全解除

		if(item.meta["Add Global State"]){
			var addId = Number(item.meta["Add Global State"]) || 0;
			item.addGlobalStateId = addId;
		}
		if(item.meta["Remove Global State"]){
			var removeId = Number(item.meta["Remove Global State"]) || 0;
			item.removeGlobalStateId = removeId;
		}
		if(item.addGlobalStateId > 0){
			if(item.meta["Add Global Count"]){
				var addCount = Number(item.meta["Add Global Count"]) || 1;
				item.addGlobalCount = addCount > 0 ? addCount : 1;
			}else
				item.addGlobalCount = 1;
		}
		if(item.removeGlobalStateId > 0){
			if(item.meta["Remove Global State Completely"])
				item.removeGlobalCompletely = true;
			else if(item.meta["Remove Global Count"]){
				var removeCount = Number(item.meta["Remove Global Count"]) || 1;
				item.removeGlobalCount = removeCount > 0 ? removeCount : 1;
			}else
				item.removeGlobalCount = 1;
		}
	}
};

CP.GlobalManager.loadElementCondition = function(array){
	for(var i = 1; i < array.length; i++){
		var item = array[i];
		item.globalElements = null;

		if(item.meta["Battle Element"]){
			item.globalElements = [];
			var result = item.meta["Battle Element"].trim().split(",");
			result.forEach(function(t){
				var n = Number(t) || 0;
				if(n > 0)
					item.globalElements.push(n);
			});
		}
	}
};

//得到指定id的元素對象
CP.GlobalManager.getGlobalElementById = function(elementId){
	var element = this.GLOBAL_ELEMENT_LIST[elementId - 1];
	return !!element ? element : null;
};

//狀態是否為全場狀態
CP.GlobalManager.isGlobalState = function(stateId){
	var state = $dataStates[stateId];
	if(!state)
		return false;

	return state.globalType > this.GLOBAL_TYPE_NONE;
};

//全場狀態的戰場屬性
CP.GlobalManager.getGlobalElement = function(stateId){
	if(!this.isGlobalState(stateId))
		return 0;

	return $dataStates[stateId].globalElement;
};

CP.GlobalManager.membersForGlobalStateAffected = function(stateId){
	if(!this.isGlobalState(stateId))
		return [];

	var state = $dataStates[stateId];
	switch(state.globalType){
		case this.GLOBAL_TYPE_PARTY:
			return $gameParty.members();
		case this.GLOBAL_TYPE_TROOP:
			return $gameTroop.members();
		case this.GLOBAL_TYPE_ALL:
			return $gameParty.members().concat($gameTroop.members());
		case this.GLOBAL_TYPE_CUSTOM:
			return this.customGlobalStateArea(state);
	}

	return [];
};

CP.GlobalManager.customGlobalStateArea = function(state){
	try{
		return state.globalCustomAreaEval();
	}catch(err){
		console.error(err);
		return [];
	}
};

//---------------------------
//          BattleManager
//---------------------------
CP.GlobalManager.SETUP_BATTLE = BattleManager.setup;
BattleManager.setup = function(troopId, canEscape, canLose){
	this._elementSpriteNeedUpdate = {};
	this._movableElements = []; //移動屬性標籤請求
    CP.GlobalManager.SETUP_BATTLE.call(this, troopId, canEscape, canLose);

    this.initGlobalStateMembers();
    this.initGlobalStatesAndElements();
    this.requestElementSpritesUpdateAll();
};

//初始化狀態數組
BattleManager.initGlobalStatesAndElements = function(){
	if(!this._globalStates || (this._globalStates && this._globalStates.length > 0))
		this._globalStates = [];
	this.requestGlobalStatesChange();
};

BattleManager.initGlobalElement = function(){
	this._globalElements = null;
};

//戰鬥中元素精靈的刷新請求
BattleManager.requestElementSpritesUpdate = function(elementId){
	if(elementId > 0)
		this._elementSpriteNeedUpdate[elementId] = true;
};

BattleManager.resetElementSpritesUpdate = function(elementId){
	if(elementId > 0)
		this._elementSpriteNeedUpdate[elementId] = false;
};

BattleManager.isElementSpriteUpdateRequested = function(elementId){
	return !!this._elementSpriteNeedUpdate[elementId];
};

//所有戰場元素精靈請求刷新
BattleManager.requestElementSpritesUpdateAll = function(){
	CP.GlobalManager.GLOBAL_ELEMENT_LIST.forEach((element) => {
		if(!!element)
			this.requestElementSpritesUpdate(element.id);
	});
};

//添加移動請求
BattleManager.addMovableElement = function(elementId, moveType, success){
	if(elementId > 0 && success)
		this._movableElements.push({elementId: elementId, moveType: moveType});
};

//是否有移動請求
BattleManager.isMovableElememtNeeded = function(){
	return this._movableElements.length > 0;
};

//清空移動請求
BattleManager.resetMovableElements = function(){
	this._movableElements.splice(0, this._movableElements.length);
};

//所有移動請求，格式{elementIId, moveType}
BattleManager.allMovableElements = function(){
	return this._movableElements;
};

//初始化狀態影響目標
BattleManager.initGlobalStateMembers = function(){
	this._globalStateMembers = {};
};

//刷新目標，globalState結構：{id, turn}
BattleManager.refreshGlobalStateMembers = function(){
	this.initGlobalStateMembers();
	this.globalStateData().forEach(function(globalState){
		this._globalStateMembers[globalState.id] = CP.GlobalManager.membersForGlobalStateAffected(globalState.id);
	}, this);
};

//指定狀態的影響目標
BattleManager.globalStateMembers = function(stateId){
	if(!this._globalStateMembers)
		return [];
	if(!this._globalStateMembers[stateId])
		return [];
	return this._globalStateMembers[stateId];
};

//是否存在全場狀態
BattleManager.isGlobalStateAffected = function(stateId){
	return this.globalStateIndex(stateId) >= 0;
};

//全場狀態在狀態數組的索引
BattleManager.globalStateIndex = function(stateId){
	if(!BattleManager._globalStates)
		return -1;

	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		if(state.id === stateId)
			return i;
	}

	return -1;
};

BattleManager.requestGlobalStatesChange = function(){
	var members = $gameParty.members().concat($gameTroop.members());
	members.forEach(function(battler){
		battler.requestGlobalStatesChange();
	});
	this.initGlobalElement();
	this.refreshGlobalStateMembers();
};

//添加全場狀態
BattleManager.addGlobalState = function(stateId, count){
	count = count || 1;
	if(!CP.GlobalManager.isGlobalState(stateId))
		return false;

	if(!this.isGlobalStateAffected(stateId))
		this.addNewGlobalState(stateId, count);
	else
		this.gainGlobalStateCount(stateId, count);

	this.resetGlobalStateTurns(stateId);
	this.execGlobalStateCustomEval(stateId, CP.GlobalManager.GLOBAL_EVAL_ADD);

	return true;
};

//添加新的全場狀態
BattleManager.addNewGlobalState = function(stateId, count){
	var state = $dataStates[stateId];
	var turn = state.minTurns;

	var globalState = {};
	globalState.id = stateId;
	globalState.count = 0; //疊層數定義 這裡是0，層數疊加到後面
	globalState.turns = state.autoRemovalTiming > 0 ? state.minTurns : -1;

	this._globalStates.push(globalState);
	this.gainGlobalStateCount(stateId, count);
	this.requestGlobalStatesChange();
};

//全場狀態層數變更
BattleManager.gainGlobalStateCount = function(stateId, count){
	var state = $dataStates[stateId];
	var index = this.globalStateIndex(stateId);
	var max = state.globalStateCountMax;
	if(index >= 0){
		this._globalStates[index].count += Math.floor(count);
		if(max > 0 && this._globalStates[index].count > max)
			this._globalStates[index].count = Math.floor(max);
	}
};

//重置全場狀態回合數
BattleManager.resetGlobalStateTurns = function(stateId){
	var state = $dataStates[stateId];

	if(state.autoRemovalTiming > 0){
		var index = this.globalStateIndex(stateId);
		var floatTurn = Math.random() * (state.maxTurns - state.minTurns);
		var turn = state.minTurns + Math.round(floatTurn);

		this._globalStates[index].turns = turn;
	}
};

//移除全場狀態
BattleManager.removeGlobalState = function(stateId, count){
	count = count || 1;
	if(count < 0)
		count = 1;

	if(!CP.GlobalManager.isGlobalState(stateId))
		return false;

	if(!this.isGlobalStateAffected(stateId))
		return false;

	var index = this.globalStateIndex(stateId);
	this._globalStates[index].count -= count;
	if(this._globalStates[index].count <= 0)
		this._globalStates.splice(index, 1);
	this.requestGlobalStatesChange();

	this.execGlobalStateCustomEval(stateId, CP.GlobalManager.GLOBAL_EVAL_REMOVE);

	return true;
};

//完全移除一個全場狀態
BattleManager.removeGlobalStateCompletely = function(stateId){
	return this.removeGlobalState(stateId, this.globalStateCount(stateId));
};

BattleManager.globalStateCount = function(stateId){
	if(!CP.GlobalManager.isGlobalState(stateId))
		return 0;
	var index = this.globalStateIndex(stateId);
	if(index >= 0)
		return this._globalStates[index].count;
	else
		return 0;
};

BattleManager.globalStateTurn = function(stateId){
	if(!CP.GlobalManager.isGlobalState(stateId))
		return -1;

	var index = this.globalStateIndex(stateId);
	if(index >= 0)
		return this._globalStates[index].turns;
	else
		return -1;
};

CP.GlobalManager.UPDATE_TURN_END = BattleManager.updateTurnEnd;
BattleManager.updateTurnEnd = function() {
    CP.GlobalManager.UPDATE_TURN_END.call(this);

    this.updateGlobalStateTurns();
};

//更新全場狀態回合數
BattleManager.updateGlobalStateTurns = function(){
	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		if(state.turns === -1)
			continue;

		state.turns--;
		if(state.turns <= 0)
			this.removeGlobalState(state.id, 1);
		else
			this.execGlobalStateCustomEval(state.id, CP.GlobalManager.GLOBAL_EVAL_UPDATE);
	}
};

BattleManager.globalStateData = function(){
	if(!this._globalStates)
		return [];
	else
		return this._globalStates;
}

BattleManager.globalStates = function(){
	var states = [];
	if(!this._globalStates)
		return states;

	for(var i = 0; i < this._globalStates.length; i++){
		var st = this._globalStates[i];
		states.push($dataStates[st.id]);
	}

	return states;
};

BattleManager.globalElements = function(){
	if(!this._globalElements)
		this._globalElements = this.globalElementsData();
	return this._globalElements;
};

BattleManager.globalElementsData = function(){
	var states = this.globalStates();
	var elements = [];

	states.forEach(function(state){
		if(state.globalElement > 0)
			elements.push(state.globalElement);
	});

	return elements;
};

BattleManager.hasGlobalElement = function(elementId){
	return this.globalElements().contains(elementId);
};

BattleManager.getGlobalStatesByElement = function(elementId){
	var globalStates = this.globalStates();
	var res = [];
	for(var i = 0; i < globalStates.length; i++){
		var st = globalStates[i];
		if(st.globalElement === elementId)
			res.push(st);
	}
	return res;
};

//戰場上某個元素的總和【無轉換規則】
BattleManager.globalElementCount = function(elementId){
	if(!this.hasGlobalElement(elementId))
		return 0;

	var globalStates = this.getGlobalStatesByElement(elementId);
	return globalStates.reduce((count, state) => count + this.globalStateCount(state.id), 0);
};

BattleManager.getGlobalElementCountObject = function(){
	var object = {};
	for(var i = 0; i < CP.GlobalManager.GLOBAL_ELEMENT_LIST.length; i++){
		var element = CP.GlobalManager.GLOBAL_ELEMENT_LIST[i];
		if(!!element)
			object[element.symbol] = this.globalElementCount(element.id);
	}
	return object;
};

//戰場上某個元素的總和【有轉換規則】
BattleManager.getGlobalElementCountTotal = function(elementId){
	var allElementsCount = this.getGlobalElementCountObject();
	return this.execGlobalElementTotal(elementId, allElementsCount);
};

//計算層數的規則函數
BattleManager.execGlobalElementTotal = function(elementId, elementObject){
	try{
		return CP.GlobalManager.GLOBAL_ELEMENT_TOTAL_COUNT_FUNCTION.call(this, elementId, elementObject);
	}catch(err){
		console.error(err);
		return this.globalElementCount(elementId);
	}
};

BattleManager.meetsGlobalElementConditions = function(item){
	var elements = this.globalElements();
	if(!item.globalElements || item.globalElements.length <= 0)
		return true;

	for(var i = 0; i < item.globalElements.length; i++){
		if(!this.hasGlobalElement(item.globalElements[i]))
			return false;
	}

	return true;
};

//執行額外代碼
BattleManager.execGlobalStateCustomEval = function(stateId, timing){
	var fun = null;
	var state = $dataStates[stateId];

	if(!CP.GlobalManager.isGlobalState(stateId))
		return;

	switch(timing){
		case CP.GlobalManager.GLOBAL_EVAL_ADD:
			fun = state.globalCustomEval.add;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_UPDATE:
			fun = state.globalCustomEval.update;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_REMOVE:
			fun = state.globalCustomEval.remove;
			break;
		case CP.GlobalManager.GLOBAL_EVAL_END_ACTION:
			fun = state.globalCustomEval.endAction;
			break;
	}

	if(!fun)
		return;

	try{
		fun.call(this, this._subject);
	}catch(err){
		console.error(err);
	}
};

CP.GlobalManager.START_BATTLE = BattleManager.startBattle;
BattleManager.startBattle = function(){
	CP.GlobalManager.START_BATTLE.call(this);
	if($gameTroop.turnCount() === 0)
		this.addBattleStartGlobalStates();
};

BattleManager.addBattleStartGlobalStates = function(){
	this.allAutoAddGlobalStates().forEach(function(arr){
		this.addGlobalState(arr[0], arr[1]);
	}, this);
	this.requestElementSpritesUpdateAll();
};

BattleManager.allAutoAddGlobalStates = function(){
	var globalStates = [];
	for(var i = 0; i < $dataStates.length; i++){
		var state = $dataStates[i];
		if(this.meetsAutoGlobalState(state)){
			var count = this.getAutoGlobalStateCount(state);
			if(count > 0)
			globalStates.push([state.id, count]);
		}
	}
	return globalStates;
};

BattleManager.meetsAutoGlobalState = function(state){
	if(!state)
		return false;
	else if(!CP.GlobalManager.isGlobalState(state.id))
		return false;
	else if(state.globalAutoAddData.always) //Always 無條件滿足
		return true;
	else if(state.globalAutoAddData.switches.length > 0 || state.globalAutoAddData.variables.length > 0
			|| state.globalAutoAddData.eval !== null){
		//當Always 開關 變量 eval至少有一項配置時，才開始嚴格檢測
		//嚴格檢測時，未配置項為true
		return this.meetsAutoGlobalStateSwitchConditions(state) 
			&& this.meetsAutoGlobalStateVariablesConditions(state)
			&& this.meetsAutoGlobalStateEvalConditions(state);

	}else //當所有項都未配置，不滿足條件
		return false;
};

BattleManager.meetsAutoGlobalStateSwitchConditions = function(state){
	if(state.globalAutoAddData.switches.length <= 0)
		return true; //沒有，跳過
	for(var i = 0; i < state.globalAutoAddData.switches.length; i++){
		if(!$gameSwitches.value(state.globalAutoAddData.switches[i]))
			return false;
	}
	return true;
};

BattleManager.meetsAutoGlobalStateVariablesConditions = function(state){
	if(state.globalAutoAddData.variables.length <= 0)
		return true; //沒有，跳過
	for(var i = 0; i < state.globalAutoAddData.variables.length; i++){
		var varData = state.globalAutoAddData.variables[i];
		var value = $gameVariables.value(varData.variableId);
		if(varData.min !== null && varData.max === null){
			//存在最小值而不存在最大值，即V > X
			if(value > varData.min)
				continue;
			else
				return false;
		}else if(varData.min === null && varData.max !== null){
			//存在最大值而不存在最小值，即V < X
			if(value < varData.max)
				continue;
			else
				return false;
		}else if(varData.min !== null && varData.max !== null){
			//同時存在最大值和最小值，即X1 <= V <= X2，X1 <= X2
			if(varData.min > varData.max) //X1 > X2時，直接判定失敗
				return false;
			else if(value > varData.max || value < varData.min)
				return false;
		}
	}
	return true;
};

BattleManager.meetsAutoGlobalStateEvalConditions = function(state){
	if(state.globalAutoAddData.eval === null)
		return true;
	
	try{
		return state.globalAutoAddData.eval.call(this);
	}catch(err){
		console.error(err);
		return false;
	}
};

BattleManager.getAutoGlobalStateCount = function(state){
	if(state.globalAutoAddData.count === null)
		return 1;
	try{
		return Math.round(state.globalAutoAddData.count.call(this));
	}catch(err){
		console.error(err);
		return 1;
	}
};

CP.GlobalManager.BATTLE_END_ACTION = BattleManager.endAction;
BattleManager.endAction = function(){
	this.executeGlobalStateEndActionEval();
	CP.GlobalManager.BATTLE_END_ACTION.call(this);
};

BattleManager.executeGlobalStateEndActionEval = function(){
	for(var i = 0; i < this._globalStates.length; i++){
		var state = this._globalStates[i];
		this.execGlobalStateCustomEval(state.id, CP.GlobalManager.GLOBAL_EVAL_END_ACTION);
	}
};

CP.GlobalManager.END_BATTLE = BattleManager.endBattle;
BattleManager.endBattle = function(result) {
	CP.GlobalManager.END_BATTLE.call(this, result);

	this.initGlobalStatesAndElements();
};

if(Imported.YEP_BattleEngineCore){

CP.GlobalManager.PROCESS_ACTION_SEQUENCE = BattleManager.processActionSequence;
BattleManager.processActionSequence = function(actionName, actionArgs){
	if(actionName.match(/ADD GLOBAL STATE/i))
		return this.actionAddGlobalState(actionArgs);
	if(actionName.match(/REMOVE GLOBAL STATE/i))
		return this.actionRemoveGlobalState(actionArgs);
	return CP.GlobalManager.PROCESS_ACTION_SEQUENCE.call(this, actionName, actionArgs);
};

BattleManager.actionAddGlobalState = function(actionArgs){
	var stateId = Number(actionArgs[0]) || 0;
	var count = Number(actionArgs[1]) || 1;
	if(stateId > 0 && count > 0){
		var success = this.addGlobalState(stateId, count);
		this.addMovableElement(CP.GlobalManager.getGlobalElement(stateId)
			, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
	}
	return true;
};

BattleManager.actionRemoveGlobalState = function(actionArgs){
	var stateId = Number(actionArgs[0]) || 0;
	var count = Number(actionArgs[1]) || 1;
	var success = false;

	if(stateId > 0){
		if(!!actionArgs[1] && actionArgs[1].trim().toUpperCase() == "ALL")
			success = this.removeGlobalStateCompletely(stateId);
		else if(count > 0)
			success = this.removeGlobalState(stateId, count);

		var elementId = CP.GlobalManager.getGlobalElement(stateId);
		this.requestElementSpritesUpdate(elementId);
		this.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
	}
	return true;
};

}

CP.GlobalManager.GLOBAL_ELEMENT_LIST.forEach((element) =>{
	Object.defineProperty(CP, element.symbol, {
    	get: BattleManager.getGlobalElementCountTotal.bind(BattleManager, element.id),
    	configurable: true
	});
});

//---------------------------
//          Game_BattlerBase
//---------------------------
CP.GlobalManager.INIT_BATTLER_BASE_MEMBERS = Game_BattlerBase.prototype.initMembers;
Game_BattlerBase.prototype.initMembers = function(){
	this._globalStates = null;
	this._globalStateTraitObjects = null;
	CP.GlobalManager.INIT_BATTLER_BASE_MEMBERS.call(this);
};

Game_BattlerBase.prototype.requestGlobalStatesChange = function(){
	this._globalStates = null;
	this._globalStateTraitObjects = null;
};

Game_BattlerBase.prototype.isChangeGlobalStatesRequested = function(){
	return !this._globalStates || !this._globalStateTraitObjects;
};

Game_BattlerBase.prototype.meetsGlobalElementConditions = function(item){
	return BattleManager.meetsGlobalElementConditions(item);
};

CP.GlobalManager.MEETS_SKILL_CONDITIONS = Game_BattlerBase.prototype.meetsSkillConditions;
Game_BattlerBase.prototype.meetsSkillConditions = function(skill) {
    return CP.GlobalManager.MEETS_SKILL_CONDITIONS.call(this, skill) && this.meetsGlobalElementConditions(skill);
};

CP.GlobalManager.MEETS_ITEM_CONDITIONS = Game_BattlerBase.prototype.meetsItemConditions;
Game_BattlerBase.prototype.meetsItemConditions = function(item) {
    return CP.GlobalManager.MEETS_ITEM_CONDITIONS.call(this, item) && this.meetsGlobalElementConditions(item);
};

CP.GlobalManager.IS_BATTLER_STATE_AFFECTED = Game_BattlerBase.prototype.isStateAffected;
Game_BattlerBase.prototype.isStateAffected = function(stateId) {
    if(this.isGlobalStateAffected(stateId))
    	return true;

    return CP.GlobalManager.IS_BATTLER_STATE_AFFECTED.call(this, stateId);
};

Game_BattlerBase.prototype.isGlobalStateAffected = function(stateId){
	return BattleManager.isGlobalStateAffected(stateId) 
		&& BattleManager.globalStateMembers(stateId).contains(this); 
};

Game_BattlerBase.prototype.globalStateList = function(){
	var states = [];

	BattleManager.globalStateData().forEach(function(globalState){
		if(this.isGlobalStateAffected(globalState.id))
			states.push(globalState.id);
	}, this);

	return states;
};

Game_BattlerBase.prototype.globalStates = function(){
	if(this.isChangeGlobalStatesRequested())
		this._globalStates = this.globalStateList();
	return this._globalStates.map((stateId) => $dataStates[stateId]).filter((state) => !!state);
};

CP.GlobalManager.BATTLER_STATES = Game_BattlerBase.prototype.states;
Game_BattlerBase.prototype.states = function(){
	return CP.GlobalManager.BATTLER_STATES.call(this).concat(this.globalStates());
};

CP.GlobalManager.BATTLER_BASE_TRAIT_OBJECTS = Game_BattlerBase.prototype.traitObjects;
Game_BattlerBase.prototype.traitObjects = function(){
	return CP.GlobalManager.BATTLER_BASE_TRAIT_OBJECTS.call(this).concat(this.globalStateTraitObjects());
};

Game_BattlerBase.prototype.globalStateTraitObjects = function(){
	if(!this._globalStateTraitObjects)
		this._globalStateTraitObjects = this.globalStateTraitObjectList();
	return this._globalStateTraitObjects.map((stateId) => $dataStates[stateId]).filter((state) => !!state);
};

Game_BattlerBase.prototype.globalStateTraitObjectList = function(){
	var others = [];
	BattleManager.globalStateData().forEach(function(globalState){
		var curSt = $dataStates[globalState.id];
		if(this.isGlobalStateAffected(globalState.id)){
			var count = globalState.count - 1;
			for(var i = 0; i < count; i++)
				others.push(curSt.globalNextState);
		}
	}, this);
	return others;
};

CP.GlobalManager.BATTLER_BASE_REFRESH = Game_BattlerBase.prototype.refresh;
Game_BattlerBase.prototype.refresh = function(){
	this.requestGlobalStatesChange();
	if($gameParty.inBattle())
		BattleManager.refreshGlobalStateMembers();
	CP.GlobalManager.BATTLER_BASE_REFRESH.call(this);
};

if(Imported.YEP_BuffsStatesCore){
CP.GlobalManager.BATTLER_STATE_TURNS = Game_BattlerBase.prototype.stateTurns;
Game_BattlerBase.prototype.stateTurns = function(stateId){
    if(this.isGlobalStateAffected(stateId))
    	return BattleManager.globalStateTurn(stateId);
    return CP.GlobalManager.BATTLER_STATE_TURNS.call(this, stateId);
};
}

//---------------------------
//       Game_Battler
//---------------------------
CP.GlobalManager.BATTLER_PERFORM_ACTION = Game_Battler.prototype.performAction;
Game_Battler.prototype.performAction = function(action){
	CP.GlobalManager.BATTLER_PERFORM_ACTION.call(this, action);
	action.execGlobalStateAction();
};

//---------------------------
//          Game_Action
//---------------------------
Game_Action.prototype.execGlobalStateAction = function(){
	var addId = this.getAddGlobalStateId();
	var addCount = this.getAddGlobalStateCount();
	var removeId = this.getRemoveGlobalStateId();
	var removeCount = this.getRemoveGlobalStateCount();
	var isCompletely = this.isRemoveGlobalCompletely();
	var success = false;
	if(addId > 0 && addCount > 0){
		success = BattleManager.addGlobalState(addId, addCount);
		BattleManager.addMovableElement(CP.GlobalManager.getGlobalElement(addId)
			, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
	}
	else if(removeId > 0){
		var removeElement = CP.GlobalManager.getGlobalElement(removeId);
		if(isCompletely){
			success = BattleManager.removeGlobalStateCompletely(removeId);
			BattleManager.requestElementSpritesUpdate(removeElement);
			BattleManager.addMovableElement(removeElement, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}else if(removeCount > 0){
			success = BattleManager.removeGlobalState(removeId, removeCount);
			BattleManager.requestElementSpritesUpdate(removeElement);
			BattleManager.addMovableElement(removeElement, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}
	}
};

Game_Action.prototype.getAddGlobalStateId = function(){
	var item = this.item();
	if(!!item)
		return item.addGlobalStateId;
	else
		return 0;
};

Game_Action.prototype.getAddGlobalStateCount = function(){
	var item = this.item();
	if(!!item)
		return item.addGlobalCount;
	else
		return 0;
};

Game_Action.prototype.getRemoveGlobalStateId = function(){
	var item = this.item();
	if(!!item)
		return item.removeGlobalStateId;
	else
		return 0;
};

Game_Action.prototype.getRemoveGlobalStateCount = function(){
	var item = this.item();
	if(!!item)
		return item.removeGlobalCount;
	else
		return 0;
};

Game_Action.prototype.isRemoveGlobalCompletely = function(){
	var item = this.item();
	if(!!item && item.removeGlobalStateId > 0)
		return item.removeGlobalCompletely;
	else
		return false;
};

//---------------------------
//          Game_Interpreter
//---------------------------
CP.GlobalManager.PLUGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args) {
	CP.GlobalManager.PLUGIN_COMMAND.call(this, command, args);

	if($gameParty.inBattle() && command == 'GlobalState'){
		var action = args[0];
		var stateId = Number(args[1]) || 0;
		var count = !!args[2] && args[2].toUpperCase() === "ALL" ? -1 : Number(args[2]) || 1;
		var elementId = CP.GlobalManager.getGlobalElement(stateId);
		var success = false;
		if(count > 0){
			if(action.toUpperCase() == "ADD"){
				success = BattleManager.addGlobalState(stateId, count);
				BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD, success);
			}else if(action.toUpperCase() == "REMOVE"){
				success = BattleManager.removeGlobalState(stateId, count);
				BattleManager.requestElementSpritesUpdate(elementId);
				BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
			}
		}else if(count === -1 && action.toUpperCase() == "REMOVE"){
			success = BattleManager.removeGlobalStateCompletely(stateId);
			BattleManager.requestElementSpritesUpdate(elementId);
			BattleManager.addMovableElement(elementId, Sprite_MovableGlobalElement.MOVE_TYPE_BACK, success);
		}
	}
};

//---------------------------
//          Game_Switches
//---------------------------
CP.GlobalManager.SWITCHES_ON_CHANGE = Game_Switches.prototype.onChange;
Game_Switches.prototype.onChange = function(){
	CP.GlobalManager.SWITCHES_ON_CHANGE.call(this);
	if($gameParty.inBattle())
		BattleManager.requestGlobalStatesChange();
};

//---------------------------
//          Game_Variables
//---------------------------
CP.GlobalManager.VARIABLES_ON_CHANGE = Game_Variables.prototype.onChange;
Game_Variables.prototype.onChange = function(){
	CP.GlobalManager.VARIABLES_ON_CHANGE.call(this);
	if($gameParty.inBattle())
		BattleManager.requestGlobalStatesChange();
};

//----------------------------
//          Window_BattleItem
//-----------------------------
CP.GlobalManager.BATTLE_ITEM_INCLUDES = Window_BattleItem.prototype.includes;
Window_BattleItem.prototype.includes = function(item) {
    var result = CP.GlobalManager.BATTLE_ITEM_INCLUDES.call(this, item);

    if(item && item.globalElements && item.globalElements.length > 0)
    	result = true;

    return result;
};

//---------------------------
//    Sprite_GlobalElementBase
//---------------------------
function Sprite_GlobalElementBase(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElementBase.prototype = Object.create(Sprite_Base.prototype);
Sprite_GlobalElementBase.prototype.constructor = Sprite_GlobalElementBase;

Sprite_GlobalElementBase.prototype.initialize = function(elementId){
	this._elementId = elementId;
	Sprite_Base.prototype.initialize.call(this);
	this.setupElementData();
	this.requestChange(); //構造之後馬上請求刷新
};

//請求刷新，如果不需要刷新的情況，空函數
Sprite_GlobalElementBase.prototype.requestChange = function(){};

//精靈是否已請求刷新，默認完全不處理
Sprite_GlobalElementBase.prototype.isChangeRequested = function(){
	return false;
};

//繪製完成時，恢復請求狀態
Sprite_GlobalElementBase.prototype.resetChange = function(){};

//讀取當前的元素data對象
Sprite_GlobalElementBase.prototype.elementData = function(){
	return CP.GlobalManager.getGlobalElementById(this._elementId);
};

Sprite_GlobalElementBase.prototype.setupElementData = function(){
	var element = this.elementData();
	if(!!element)
		this.setupElementDataAll(element);
};

Sprite_GlobalElementBase.prototype.setupElementDataAll = function(element){
	this.setupBitmap(element);
	this.setupAnchor(element);
	this.setupPosition(element);
};

Sprite_GlobalElementBase.prototype.setupBitmap = function(element){
	this.bitmap = element.image;
};

Sprite_GlobalElementBase.prototype.setupAnchor = function(element){
	this.anchor.set(element.anchorX, element.anchorY);
};

Sprite_GlobalElementBase.prototype.setupPosition = function(element){
	this.move(element.posX.call(this, element.id), element.posY.call(this, element.id));
};

Sprite_GlobalElementBase.prototype.update = function(){
	Sprite_Base.prototype.update.call(this);
	this.updateElementChange();
};

Sprite_GlobalElementBase.prototype.updateElementChange = function(){
	if(this.isChangeRequested()){
		this.refreshAll();
		this.resetChange();
	}
};

//刷新主函數
Sprite_GlobalElementBase.prototype.refreshAll = function(){
	this.changeElementVisibilty();
};

//變換元素精靈的可見性
Sprite_GlobalElementBase.prototype.changeElementVisibilty = function(){
	var ev = this.isElementVisibility();
	if(this.visible && !ev)
		this.hide();
	else if(!this.visible && ev)
		this.show();
};

Sprite_GlobalElementBase.prototype.isElementVisibility = function(){
	return true;
};

//---------------------------
//    Sprite_GlobalElement
//---------------------------
function Sprite_GlobalElement(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElement.prototype = Object.create(Sprite_GlobalElementBase.prototype);
Sprite_GlobalElement.prototype.constructor = Sprite_GlobalElement;

Sprite_GlobalElement.prototype.initialize = function(elementId){
	Sprite_GlobalElementBase.prototype.initialize.call(this, elementId);
};

Sprite_GlobalElement.prototype.setupElementDataAll = function(element){
	Sprite_GlobalElementBase.prototype.setupElementDataAll.call(this, element);
	this.setupTextData(element);
};

Sprite_GlobalElement.prototype.setupTextData = function(element){
	if(!this._textSprite){
		this._textSprite = new Sprite_GlobalElement.Sprite_Text(this.bitmap.width + 24, this.bitmap.height + 24);
		this.addChild(this._textSprite);
	}

	this._textSprite.setFontFace(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.font);
	this._textSprite.setFontSize(CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.size);
	this._textSprite.changeTextColor(element.countColor);
};

//精靈是否已請求刷新
Sprite_GlobalElement.prototype.isChangeRequested = function(){
	return BattleManager.isElementSpriteUpdateRequested(this._elementId);
};

Sprite_GlobalElement.prototype.requestChange = function(){
	BattleManager.requestElementSpritesUpdate(this._elementId);
};

//繪製完成時，恢復請求狀態
Sprite_GlobalElement.prototype.resetChange = function(){
	BattleManager.resetElementSpritesUpdate(this._elementId);
};

//當前戰場元素的默認層數，作為精靈是否可見的條件以及繪製內容
Sprite_GlobalElement.prototype.elementCount = function(){
	return BattleManager.globalElementCount(this._elementId);
};

//update部分
//刷新主函數
Sprite_GlobalElement.prototype.refreshAll = function(){
	Sprite_GlobalElementBase.prototype.refreshAll.call(this);
	this.refreshText();
};


Sprite_GlobalElement.prototype.isElementVisibility = function(){
	return this.elementCount() > 0;
};

Sprite_GlobalElement.prototype.refreshText = function(){
	this._textSprite.clear();
	this.drawAllCount();
};

Sprite_GlobalElement.prototype.drawAllCount = function(){
	var element = this.elementData();
	if(!!element){
		var tx = element.countX.call(this, element.id);
		var ty = element.countY.call(this, element.id);
		var text = CP.GlobalManager.GLOBAL_ELEMENT_TEXT_DATA.text.format(this.elementCount());
		this._textSprite.drawText(text, tx, ty, this.bitmap.width);
	}
};

//---------------------------
// Sprite_GlobalElement.Sprite_Text
// 戰鬥元素內部類，文字繪製
//---------------------------
Sprite_GlobalElement.Sprite_Text = function(){
	this.initialize.apply(this, arguments);
};

Sprite_GlobalElement.Sprite_Text.prototype = Object.create(Sprite_Base.prototype);
Sprite_GlobalElement.Sprite_Text.prototype.constructor = Sprite_GlobalElement.Sprite_Text;

Sprite_GlobalElement.Sprite_Text.prototype.initialize = function(width, height){
	Sprite_Base.prototype.initialize.call(this);
	this.bitmap = new Bitmap(width, height);
	this.move(0, 0);
};

Sprite_GlobalElement.Sprite_Text.prototype.clear = function(){
	this.bitmap.clear();
};

Sprite_GlobalElement.Sprite_Text.prototype.setFontFace = function(fontFace){
	this.bitmap.fontFace = fontFace;
};

Sprite_GlobalElement.Sprite_Text.prototype.setFontSize = function(size){
	this.bitmap.fontSize = size;
};

Sprite_GlobalElement.Sprite_Text.prototype.changeTextColor = function(color){
	this.bitmap.textColor = color;
};

Sprite_GlobalElement.Sprite_Text.prototype.drawText = function(text, x, y, maxWidth, align){
	if(align ===  undefined)
		align = "left";

	this.bitmap.drawText(text, x, y, maxWidth, this.bitmap.fontSize + 10, align);
};

//---------------------------
// Sprite_MovableGlobalElement
// 可以動的，做移動動畫
//---------------------------
function Sprite_MovableGlobalElement(){
	this.initialize.apply(this, arguments);
};

Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD = 1; //前進，從起點到元素位
Sprite_MovableGlobalElement.MOVE_TYPE_BACK = 2; //返回，從元素位返回起點

Sprite_MovableGlobalElement.prototype = Object.create(Sprite_GlobalElementBase.prototype);
Sprite_MovableGlobalElement.prototype.constructor = Sprite_MovableGlobalElement;

Sprite_MovableGlobalElement.prototype.initialize = function(elementId, moveType){
	this._duration = 0; //運動幀數
	this._stoped = false; //停止標記
	this._targetX = null;
	this._targetY = null;
	this._targetOpacity = null;
	this._moveType = moveType;
	Sprite_GlobalElementBase.prototype.initialize.call(this, elementId);
};

Sprite_MovableGlobalElement.prototype.hasStoped = function(){
	return !!this._stoped;
};

Sprite_MovableGlobalElement.prototype.isForward = function(){
	return this._moveType === Sprite_MovableGlobalElement.MOVE_TYPE_FORWARD;
};

Sprite_MovableGlobalElement.prototype.isBack = function(){
	return this._moveType === Sprite_MovableGlobalElement.MOVE_TYPE_BACK;
};

Sprite_MovableGlobalElement.prototype.setupElementDataAll = function(element){
	Sprite_GlobalElementBase.prototype.setupElementDataAll.call(this, element);
	this.setupOpacity(element);
}

Sprite_MovableGlobalElement.prototype.setupPosition = function(element){
	if(this.isForward())
		this.setupHomePosition(element);
	else if(this.isBack())
		Sprite_GlobalElementBase.prototype.setupPosition.call(this, element);
};

Sprite_MovableGlobalElement.prototype.setupHomePosition = function(element){
	var x = CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.x.call(this, element.id);
	var y = CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.y.call(this, element.id);
	this.move(x, y);
};

Sprite_MovableGlobalElement.prototype.setupOpacity = function(element){
	if(this.isForward())
		this.opacity = CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN;
	else
		this.opacity = 255;
};

Sprite_MovableGlobalElement.prototype.targetX = function(){
	var element = this.elementData();
	if(this.isForward())
		return element.posX.call(this, element.id);
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.x.call(this, element.id);
	else
		return null;
};

Sprite_MovableGlobalElement.prototype.targetY = function(){
	var element = this.elementData();
	if(this.isForward())
		return element.posY.call(this, element.id);
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_HOME_POSITION.y.call(this, element.id);
	else
		return null;
};

Sprite_MovableGlobalElement.prototype.targetOpacity = function(){
	if(this.isForward())
		return 255;
	else if(this.isBack())
		return CP.GlobalManager.GLOBAL_ELEMENT_OPACITY_MIN;
};

//開始移動
Sprite_MovableGlobalElement.prototype.startMove = function(duration){
	this._targetX = this.targetX();
	this._targetY = this.targetY();
	this._targetOpacity = this.targetOpacity();
	this._duration = duration;
};

Sprite_MovableGlobalElement.prototype.stopMove = function(){
	this._targetX = null;
	this._targetY = null;
	this._targetOpacity = null;
	this._duration = 0;
	this._stoped = true;
};

Sprite_MovableGlobalElement.prototype.update = function(){
	Sprite_GlobalElementBase.prototype.update.call(this);
	this.updateMovement();
};

Sprite_MovableGlobalElement.prototype.isMoving = function(){
	return this._duration > 0 && this._targetX !== null && this._targetY !== null;
};

Sprite_MovableGlobalElement.prototype.updateMovement = function(){
	if(this.isMoving())
		this.updatePosition();
	else{
		this.requestMainElementspriteChange();
		this.stopMove();
	}
};

Sprite_MovableGlobalElement.prototype.updatePosition = function(){
	this.x = (this.x * (this._duration - 1) + this._targetX) / this._duration;
	this.y = (this.y * (this._duration - 1) + this._targetY) / this._duration;
	this.opacity = (this.opacity * (this._duration - 1) + this._targetOpacity) / this._duration;
	this._duration--;
};

Sprite_MovableGlobalElement.prototype.requestMainElementspriteChange = function(){
	var element = this.elementData();
	if(!!element && element.id > 0)
		BattleManager.requestElementSpritesUpdate(element.id);
};

//---------------------------
//    Scene_Battle
//---------------------------
CP.GlobalManager.SCENE_BATTLE_CREATE_DISPLAY_OBJECTS = Scene_Battle.prototype.createDisplayObjects;
Scene_Battle.prototype.createDisplayObjects = function(){
	CP.GlobalManager.SCENE_BATTLE_CREATE_DISPLAY_OBJECTS.call(this);
	this.initMoveableElementSpriteList();
	this.createAllGlobalElementSprites();
};

Scene_Battle.prototype.createAllGlobalElementSprites = function(){
	this._globalElementSprites = {};
	for(var i = 0; i < CP.GlobalManager.GLOBAL_ELEMENT_LIST.length; i++){
		var element = CP.GlobalManager.GLOBAL_ELEMENT_LIST[i];
		this._globalElementSprites[element.id] = new Sprite_GlobalElement(element.id);
		this.addChild(this._globalElementSprites[element.id]);
	}
};

Scene_Battle.prototype.initMoveableElementSpriteList = function(){
	this._movableElementSprites = [];
};

CP.GlobalManager.SCENE_BATTLE_UPDATE = Scene_Battle.prototype.update;
Scene_Battle.prototype.update = function(){
	CP.GlobalManager.SCENE_BATTLE_UPDATE.call(this);
	this.updateMovableElementSprites();
};

Scene_Battle.prototype.updateMovableElementSprites = function(){
	this.updateMovableElementSpritesAdd();
	this.updateMovableElementSpritesRemove();
};

Scene_Battle.prototype.updateMovableElementSpritesAdd = function(){
	BattleManager.allMovableElements().forEach(function(data){
		if(data.elementId > 0){
			var sprite = new Sprite_MovableGlobalElement(data.elementId, data.moveType);
			this._movableElementSprites.push(sprite);
			this.addChild(sprite);
			sprite.startMove(CP.GlobalManager.GLOBAL_ELEMENT_MOVE_TIME);
		}
	}, this);
	BattleManager.resetMovableElements();
};

Scene_Battle.prototype.updateMovableElementSpritesRemove = function(){
	for(var i = 0; i < this._movableElementSprites.length; i++){
		var sprite = this._movableElementSprites[i];
		if(this.canMovableElementSpriteRemove(sprite)){
			this.removeChild(sprite);
			this._movableElementSprites[i] = null;
		}
	}
	this._movableElementSprites = this._movableElementSprites.filter((sprite) => !!sprite);
};

Scene_Battle.prototype.canMovableElementSpriteRemove = function(sprite){
	if(!sprite)
		return false;
	if(!sprite.hasStoped())
		return false;
	if(sprite.isForward()){
		var element = sprite.elementData();
		if(element && element.id > 0){
			var mainSprite = this._globalElementSprites[element.id];
			if(!!mainSprite && mainSprite.visible)
				return true;
			else
				return false;
		}else
			return false;
	}else if(sprite.isBack())
		return true;
	else
		return false;
};

//元素移動的時候，阻塞戰鬥
CP.GlobalManager.SCENE_BATTLE_IS_BUSY = Scene_Battle.prototype.isBusy;
Scene_Battle.prototype.isBusy = function(){
	if(this.hasAnyMovableElementSpriteMoving())
		return true;
	else
		return CP.GlobalManager.SCENE_BATTLE_IS_BUSY.call(this);
};

Scene_Battle.prototype.hasAnyMovableElementSpriteMoving = function(){
	if(this._movableElementSprites.length <= 0)
		return false;
	else
		return this._movableElementSprites.some((sprite) => sprite.isMoving());
};